﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace SquareChaseBot
{
    /// <summary>
    /// The SquareChase game bot player.
    /// </summary>
    internal class BotPlayer
    {
        #region Constants

        /// <summary>
        /// The ProcessName of the Square Chase game process.
        /// </summary>
        const string SquareChaseProcessName = "SquareChase";

        /// <summary>
        /// The height of the square (i.e. the target in the game) in pixels.
        /// </summary>
        const int SquareHeight = 25;

        /// <summary>
        /// The width of the square (i.e. the target in the game) in pixels.
        /// </summary>
        const int SquareWidth  = SquareHeight;

        #endregion

        #region Private Methods

        /// <summary>
        /// Builds a list of points to click inside the game area.
        /// </summary>
        /// <param name="rectangle">
        /// The game area to cover in clicks.
        /// </param>
        /// <returns>
        /// List&gt;Point&lt;
        /// <para>
        /// Points to click.
        /// </para>
        /// </returns>
        private List<Point> BuildTargetPoints(RECT rectangle)
        {
            List<Point> points = new List<Point>();
            
            for (int horizontal = rectangle.Top; horizontal <= rectangle.Bottom; horizontal+=SquareHeight)
            {
                for (int vertical = rectangle.Left; vertical <= rectangle.Right; vertical+=SquareWidth)
                {
                    Point point = new Point(vertical, horizontal);

                    points.Add(point);
                }
            }

            return points;
        }

        /// <summary>
        /// Gets the process running the SquareChase game.
        /// </summary>
        /// <returns>
        /// The SquareChase game progress, if running; else, null.
        /// </returns>
        private Process GetGameProcess()
        {
            var gameProcess = 
                Process.GetProcessesByName(SquareChaseProcessName);

            return gameProcess.FirstOrDefault();
        }
        
        #endregion

        #region Internal Methods

        /// <summary>
        /// Plays the game for the specified number of seconds.
        /// </summary>
        /// <param name="secondsToPlay">
        /// The number of seconds to play the game. A number between 1 and 10.
        /// </param>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// <paramref name="secondsToPlay"/> was not within the 1-10 range.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// Game process not found.
        /// </exception>
        internal void Play(int secondsToPlay)
        {
            /**
             * Parameter validation.
             */
            if (secondsToPlay < 1 || secondsToPlay > 10)
            {
                throw new ArgumentOutOfRangeException("secondsToPlay",
                    secondsToPlay,
                    "Expected a value between 1 and 10 (inclusive).");
            }


            /**
             * Find the game process.
             */
            Process gameProcess = GetGameProcess();

            if (gameProcess == null)
            {
                throw new InvalidOperationException(
                    "'" + SquareChaseProcessName + "' process not found."
                    + " Is the game running?");
            }


            /**
             * Find the client area (game playing field).
             */
            RECT gameClientArea;

            Window.GetClientRect(gameProcess.MainWindowHandle,
                out gameClientArea);


            /**
             * Map client area relative to screen.
             */
            Window.MapWindowPoints(GetGameProcess().MainWindowHandle,
                Window.HWND_DESKTOP, ref gameClientArea, 2);


            /**
             * Build list of pixels to click.
             */
            List<Point> targetPoints = BuildTargetPoints(gameClientArea);


            /**
             * Begin clicking.
             */
            Console.WriteLine("Playing game for {0:N0} seconds.", 
                secondsToPlay);

            DateTime playStarted = DateTime.Now;

            while ((DateTime.Now - playStarted).TotalSeconds < secondsToPlay)
            {
                // for each Point point in Points
                //   Mouse.Click(Point)

                foreach (Point targetPoint in targetPoints)
                {
                    //Console.WriteLine("Clicking ({0:N0}, {1:N0})",
                    //    targetPoint.X, targetPoint.Y);
                    
                    // Move mouse
                    Cursor.SetCursorPos(targetPoint.X, targetPoint.Y);

                    // Click
                    Mouse.LeftClick();

                    // Wait?
                    System.Threading.Thread.Sleep(10);
                }
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initialises a new instance of the BotPlayer class.
        /// </summary>
        internal BotPlayer()
        { }

        #endregion
    }
}
